/**
 * Copyright (C) 2006-2012 phloc systems
 * http://www.phloc.com
 * office[at]phloc[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.phloc.scopes.web.fileupload.io;

import java.io.File;
import java.io.IOException;

import com.phloc.commons.io.file.FileOperations;

/**
 * Strategy for deleting files.
 * <p>
 * There is more than one way to delete a file. You may want to limit access to
 * certain directories, to only delete directories if they are empty, or maybe
 * to force deletion.
 * <p>
 * This class captures the strategy to use and is designed for user subclassing.
 * 
 * @author Stephen Colebourne
 * @version $Id: FileDeleteStrategy.java 723942 2008-12-06 01:24:06Z sebb $
 * @since Commons IO 1.3
 */
public class FileDeleteStrategy
{

  /**
   * The singleton instance for normal file deletion, which does not permit the
   * deletion of directories that are not empty.
   */
  public static final FileDeleteStrategy NORMAL = new FileDeleteStrategy ("Normal");
  /**
   * The singleton instance for forced file deletion, which always deletes, even
   * if the file represents a non-empty directory.
   */
  public static final FileDeleteStrategy FORCE = new ForceFileDeleteStrategy ();

  /** The name of the strategy. */
  private final String m_sName;

  // -----------------------------------------------------------------------
  /**
   * Restricted constructor.
   * 
   * @param name
   *        the name by which the strategy is known
   */
  protected FileDeleteStrategy (final String name)
  {
    this.m_sName = name;
  }

  // -----------------------------------------------------------------------
  /**
   * Deletes the file object, which may be a file or a directory. All
   * <code>IOException</code>s are caught and false returned instead. If the
   * file does not exist or is null, true is returned.
   * <p>
   * Subclass writers should override {@link #doDelete(File)}, not this method.
   * 
   * @param fileToDelete
   *        the file to delete, null returns true
   * @return true if the file was deleted, or there was no such file
   */
  public boolean deleteQuietly (final File fileToDelete)
  {
    if (fileToDelete == null || fileToDelete.exists () == false)
    {
      return true;
    }
    try
    {
      return doDelete (fileToDelete);
    }
    catch (final IOException ex)
    {
      return false;
    }
  }

  /**
   * Deletes the file object, which may be a file or a directory. If the file
   * does not exist, the method just returns.
   * <p>
   * Subclass writers should override {@link #doDelete(File)}, not this method.
   * 
   * @param fileToDelete
   *        the file to delete, not null
   * @throws NullPointerException
   *         if the file is null
   * @throws IOException
   *         if an error occurs during file deletion
   */
  public void delete (final File fileToDelete) throws IOException
  {
    if (fileToDelete.exists () && doDelete (fileToDelete) == false)
    {
      throw new IOException ("Deletion failed: " + fileToDelete);
    }
  }

  /**
   * Actually deletes the file object, which may be a file or a directory.
   * <p>
   * This method is designed for subclasses to override. The implementation may
   * return either false or an <code>IOException</code> when deletion fails. The
   * {@link #delete(File)} and {@link #deleteQuietly(File)} methods will handle
   * either response appropriately. A check has been made to ensure that the
   * file will exist.
   * <p>
   * This implementation uses {@link File#delete()}.
   * 
   * @param fileToDelete
   *        the file to delete, exists, not null
   * @return true if the file was deleteds
   * @throws NullPointerException
   *         if the file is null
   * @throws IOException
   *         if an error occurs during file deletion
   */
  protected boolean doDelete (final File fileToDelete) throws IOException
  {
    return fileToDelete.delete ();
  }

  // -----------------------------------------------------------------------
  /**
   * Gets a string describing the delete strategy.
   * 
   * @return a string describing the delete strategy
   */
  @Override
  public String toString ()
  {
    return "FileDeleteStrategy[" + m_sName + "]";
  }

  // -----------------------------------------------------------------------
  /**
   * Force file deletion strategy.
   */
  static class ForceFileDeleteStrategy extends FileDeleteStrategy
  {
    /** Default Constructor */
    ForceFileDeleteStrategy ()
    {
      super ("Force");
    }

    /**
     * Deletes the file object.
     * <p>
     * This implementation uses <code>FileUtils.forceDelete() <code>
     * if the file exists.
     * 
     * @param fileToDelete
     *        the file to delete, not null
     * @return Always returns <code>true</code>
     * @throws NullPointerException
     *         if the file is null
     * @throws IOException
     *         if an error occurs during file deletion
     */
    @Override
    protected boolean doDelete (final File fileToDelete) throws IOException
    {
      FileOperations.deleteFile (fileToDelete);
      return true;
    }
  }
}
